#include "test_scheme.h"
#include <iostream>
#include <chrono>
#include <iomanip>
using namespace std;

// 测试参数
std::vector<Context *> testParams = {
    new Context(12, { 0x7ffffec001, 0x8000016001 }, { 0x40002001 }, 65537,
    DefaultSigma), // 39 + 39 bits, 30 bits

    new Context(13, { 0x3fffffffef8001, 0x4000000011c001, 0x40000000120001 }, { 0x7ffffffffb4001 }, 65537,
    DefaultSigma), // 54 + 54 + 54 bits, 55 bits

    new Context(12, { 0x800004001, 0x800008001 }, { 0x80014001 }, 65537,
    DefaultSigma), // 2*35 bits, 31 bits

    new Context(13, { 0x7fffffffe0001, 0x7fffffffcc001, 0x3ffffffffc001 }, { 0x4000000024001 }, 65537,
    DefaultSigma), // 2*51 + 50 bits, 50 bits
    
    new Context(15,
    { 36028797017456641, 36028797014704129, 36028797014573057, 36028797014376449, 36028797013327873, 36028797013000193,
    36028797012606977, 36028797010444289, 36028797009985537, 36028797005856769, 36028797005529089, 36028797005135873,
    36028797003694081, 36028797003563009, 36028797001138177 },
    { 72057594037338113 }, 65537,
    DefaultSigma), // 15*54 bits, 55 bits
};

std::vector<Context *> testBootstrapParams = {
    new Context(15,
    { 36028797017456641, 36028797014704129, 36028797014573057, 36028797014376449, 36028797013327873, 36028797013000193,
    36028797012606977, 36028797010444289, 36028797009985537, 36028797005856769, 36028797005529089, 36028797005135873,
    36028797003694081, 36028797003563009, 36028797001138177 },
    { 72057594037338113 }, 257,
    DefaultSigma), // 15*54 bits, 55 bits
};

bool isPrime(uint64_t n) {
    if (n <= 1) {
        return false;
    }
    if (n == 2) {
        return true;
    }
    if (n % 2 == 0) {
        return false;
    }
    for (uint64_t i = 3; i <= std::sqrt(n); i += 2) {
        if (n % i == 0) return false;
    }
    
    return true;
}

void TestScheme::GetPrimes(uint64_t logN, uint64_t bit, 
    vector<uint64_t>& qVec, vector<uint64_t>& pVec, int L, int K)
{
    uint64_t N = 1L << logN;
    uint64_t a = (1L << bit) + 1;
    for(int i = 0; i < K; i++) {
        while (true) {
            a -= (2 * N);
            if (isPrime(a)) {
                pVec.push_back(a);
                break;
            }
        } 
    }
    for(int i = 0; i < L; i++) {
        while (true) {
            a -= (2 * N);
            if (isPrime(a)) {
                qVec.push_back(a);
                break;
            }
        }  
    }
}

Context* TestScheme::GetParams(long logN, int lambda)
{
    switch (lambda) {
        case 128: {
            switch (logN) {
                case 15: {
                    vector<uint64_t> qVec = { 36028797017456641, 36028797014704129, 36028797014573057, 36028797014376449, 36028797013327873, 
                                              36028797013000193, 36028797012606977, 36028797010444289, 36028797009985537, 36028797005856769, 
                                              36028797005529089, 36028797005135873, 36028797003694081, 36028797003563009, 36028797001138177 };
                        vector<uint64_t> pVec = { 72057594037338113 };
                    return new Context(logN, qVec, pVec, 65537, DefaultSigma);
                }
                case 14: {
                    vector<uint64_t> qVec = {36028797016178689, 36028797014704129, 36028797014573057, 36028797014376449, 
                                            36028797014081537, 36028797013327873, 36028797013098497 };
                    vector<uint64_t> pVec = {36028797017456641};
                    return new Context(logN, qVec, pVec, 65537, DefaultSigma);
                }
                case 13: {
                    vector<uint64_t> qVec = {36028797017571329, 36028797017456641, 36028797017276417};
                    vector<uint64_t> pVec = {36028797018652673, };
                    return new Context(logN, qVec, pVec, 65537, DefaultSigma);
                }
                case 12: {
                    return new Context(logN, {0x800004001, 0x800008001}, {0x80014001}, 65537, DefaultSigma);
                }

            default:
                break;
            }
        }
        case 192: {
            switch (logN) {
                case 15: {
                    vector<uint64_t> qVec = {36028797014704129, 36028797014573057, 36028797014376449, 36028797013327873, 36028797013000193, 
                                             36028797012606977, 36028797010444289, 36028797009985537, 36028797005856769, 36028797005529089};
                    vector<uint64_t> pVec = {36028797017456641};
                    return new Context(logN, qVec, pVec, 65537, DefaultSigma);
                }
                case 14: {
                    vector<uint64_t> qVec = {36028797016178689, 36028797014704129, 36028797014573057, 36028797014376449, 36028797014081537};
                    vector<uint64_t> pVec = {36028797017456641};
                    return new Context(logN, qVec, pVec, 65537,
                        DefaultSigma);
                }
                case 13: {
                    vector<uint64_t> qVec = {1125899906629633, 1125899905744897};
                    vector<uint64_t> pVec = {1125899906826241};
                    return new Context(logN, qVec, pVec, 65537, DefaultSigma);
                }
            }
        }
        default: {
            throw std::runtime_error("No available parameters.");
        }
    }

}

void TestScheme::TestPolyMult()
{   
    std::cout << "     TestPolyMult..." << std::endl;
    // 对于函数 f(x) = x^3 + 2x^2 + x + 1 , 同态计算x = {1,2,3,...8,9,10}的结果并验证
    //1. 设置安全参数
    int logN = 13;
    int lambda = 192;
    
    //2. 获取参数
    Context *p = GetParams(logN, lambda);
    TestContext *testctx = nullptr;
    try {
        testctx = GenTestParams(p);
    } catch (std::exception &e) {
        throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
    }
    if (testctx->params->PCount() == 0) {
        throw std::runtime_error("#Pi is empty");
    }
    //3. 设置消息值
    int N = 1 << logN;
    Poly *values = new Poly();
    Poly *poly = new Poly();
    values->Coeffs.resize(1, std::vector<uint64_t>(N, 0));
    poly->Coeffs.resize(1, std::vector<uint64_t>(N, 0));
    for(int i = 0; i < 10; i++) {
        values->Coeffs[0][i] = i;
        poly->Coeffs[0][i] = pow(i, 3) + 2 * pow(i, 2) + i + 1;
    }
    //4. 加密消息值
    Plaintext *plaintext = new Plaintext(testctx->params, testctx->params->QCount() - 1);
    testctx->encoder->EncodeUint(values->Coeffs[0], plaintext);
    Ciphertext *ciphertext = testctx->encryptorPk->EncryptNew(plaintext);
    //5. 计算多项式值
    Ciphertext *receiver2 =
        new Ciphertext(testctx->params, ciphertext->Degree() + ciphertext->Degree(), testctx->params->MaxLevel());
    testctx->evaluator->Mul(ciphertext, ciphertext, receiver2, MultiType::ciphertext);
    testctx->evaluator->Relinearize(receiver2, receiver2);

    Ciphertext *receiver3 =
        new Ciphertext(testctx->params, receiver2->Degree() + ciphertext->Degree(), testctx->params->MaxLevel());
    testctx->evaluator->Mul(receiver2, ciphertext, receiver3, MultiType::ciphertext);
    testctx->evaluator->Relinearize(receiver3, receiver3);
    testctx->evaluator->MulScalar(receiver2, 2, receiver2);

    testctx->evaluator->Add(ciphertext, receiver2, ciphertext);
    testctx->evaluator->Add(ciphertext, receiver3, ciphertext);
    Poly *valuesPlain = new Poly();
    valuesPlain->Coeffs.resize(1, std::vector<uint64_t>(N, 0));
    for(int i = 0; i < 10; i++) {
        valuesPlain->Coeffs[0][i] = 1;
    }
    for(int i = 10; i < N; i++) {
        valuesPlain->Coeffs[0][i] = 0;
    }
    Plaintext *plaintext1 = new Plaintext(testctx->params, testctx->params->QCount() - 1);
    testctx->encoder->EncodeUint(valuesPlain->Coeffs[0], plaintext1);
    testctx->evaluator->Add(ciphertext, plaintext1, ciphertext);
    //6. 解密验证结果正确性
    VerifyTestVectors(testctx, testctx->decryp, poly, ciphertext);

}

void TestScheme::TestRotate()
{   
    std::cout << "     TestRotate..." << std::endl;
    // 设置满槽消息 , 进行同态旋转并验证结果
    //1. 设置安全参数
    int logN = 14;
    int lambda = 128;
    //2. 获取参数
    Context *p = GetParams(logN, lambda);
    TestContext *testctx = nullptr;
    try {
        testctx = GenTestParams(p);
    } catch (std::exception &e) {
        throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
    }
    if (testctx->params->PCount() == 0) {
        throw std::runtime_error("#Pi is empty");
    }
    //3. 设置消息值
    int N = 1 << logN;
    Poly *values = new Poly();
    Poly *poly = new Poly();
    values->Coeffs.resize(1, std::vector<uint64_t>(N, 0));
    poly->Coeffs.resize(1, std::vector<uint64_t>(N, 0));
    for(int i = 0; i < N; i++) {
        values->Coeffs[0][i] = i % 100;
    }
    //4. 加密消息值
    Plaintext *plaintext = new Plaintext(testctx->params, testctx->params->QCount() - 1);
    testctx->encoder->EncodeUint(values->Coeffs[0], plaintext);
    Ciphertext *ciphertext = testctx->encryptorPk->EncryptNew(plaintext);

    //5. 计算旋转密钥
    int index = RandInt64(testctx->uSampler->prng, 255);//旋转索引
    std::vector<int> rots = { index };
    RotationKeySet *rotkey = testctx->kgen->GenRotationKeysForRotations(rots, true, testctx->sk);
    testctx->evaluator->WithKey(new EvaluationKey(testctx->rlk, rotkey));
    //6. 进行同态旋转操作
    testctx->evaluator->RotateRows(ciphertext, ciphertext);

    //7. 对消息值进行旋转
    std::vector<uint64_t> firstHalf(values->Coeffs[0].begin(),
    values->Coeffs[0].begin() + (testctx->params->N() >> 1));
    std::vector<uint64_t> secondHalf(values->Coeffs[0].begin() + (testctx->params->N() >> 1),
    values->Coeffs[0].end());
    values->Coeffs[0].clear();
    values->Coeffs[0].insert(values->Coeffs[0].end(), secondHalf.begin(), secondHalf.end());
    values->Coeffs[0].insert(values->Coeffs[0].end(), firstHalf.begin(), firstHalf.end());
    //8. 解密验证结果
    VerifyTestVectors(testctx, testctx->decryp, values, ciphertext);

}

void TestScheme::TestBootstrapping()
{
    std::cout << "     TestBootStrapping..." << std::endl;
    //1. 设置参数
    std::shared_ptr<SlotRing> slotRing = P257TestParameters();
    SlotRing basicSlotRing = slotRing->ChangeExponent(1);
    Context context(15,
        { 36028797017456641, 36028797014704129, 36028797014573057, 36028797014376449, 36028797013327873,
        36028797013000193, 36028797012606977, 36028797010444289, 36028797009985537, 36028797005856769,
        36028797005529089, 36028797005135873, 36028797003694081, 36028797003563009, 36028797001138177 },
        { 72057594037338113 }, slotRing->Prime(), 3.2);

    //2. 设置密钥
    KeyGenerator keygen(&context);
    std::pair<SecretKey *, PublicKey *> tmp = keygen.GenKeyPair();
    SecretKey sk(*tmp.first);
    PublicKey pk(*tmp.second);
    RelinearizationKey rk(*keygen.GenRelinearizationKey(&sk, 1));
    Evaluator evaluator(&context, new EvaluationKey(&rk, nullptr));
    PkEncryptor encryptor(&context, &pk);
    Decryptor decryptor(&context, &sk);
    //2. 创建消息值并加密
    poly data;
    PolyAdd(data, basicSlotRing.FromSlotValue({ 1 }, 0), basicSlotRing.R().scalarMod);
    PolyAdd(data, basicSlotRing.FromSlotValue({ 3 }, 1), basicSlotRing.R().scalarMod);
    PolyAdd(data, basicSlotRing.FromSlotValue({ 5 }, 2), basicSlotRing.R().scalarMod);
    PolyAdd(data, basicSlotRing.FromSlotValue({ 7 }, 3), basicSlotRing.R().scalarMod);
    PolyAdd(data, basicSlotRing.FromSlotValue({ 23 }, 4), basicSlotRing.R().scalarMod);
    Plaintext xPlain{ data, context.MaxLevel() };
    Ciphertext xEnc(&context, 1, context.MaxLevel());
    evaluator.lightEncoder->ScaleUp(&xPlain, &xPlain);
    encryptor.Encrypt(&xPlain, &xEnc);

    //3. 对密文进行同态乘法
    for (size_t i = 0; i < 24; ++i) {
        Ciphertext cipherMult(&context, xEnc.Degree() + xEnc.Degree(), context.MaxLevel());
        evaluator.Mul(&xEnc, &xEnc, &cipherMult, MultiType::ciphertext);
        evaluator.Relinearize(&cipherMult, &xEnc);
    }
    //3. 对密文进行同态乘法
    cout<<"     Start BootStrapping..."<<endl;
    Bootstrapper bootstrapper(context, slotRing, P257TestParametersDigitExtractor(*slotRing));
    bootstrapper.Initialize();
    bootstrapper.Bootstrapping(xEnc, sk, context);
    Plaintext result(&context, context.MaxLevel());
    decryptor.Decrypt(&xEnc, &result);
    evaluator.lightEncoder->ScaleDown(&result, &result);
    //4. 解密并输出自举结果
    poly resultPoly;
    for (int i = 0; i < result.CoeffCount(); i++) {
        resultPoly.push_back(result.value->Coeffs[0][i]);
    }
    resultPoly.resize(basicSlotRing.N());
    std::cout << " ------进行同态乘法24次后自举的结果----- " << std::endl;
    for (size_t i = 0; i < basicSlotRing.SlotGroupLen(); ++i) {
        std::cout << "i:" << i << ", " << basicSlotRing.ExtractSlotValue(resultPoly, i)[0] << std::endl;
    }
    //5. 对自举密文再进行同态乘法操作
    for (size_t i = 0; i < 16; ++i) {
        Ciphertext cipherMult(&context, xEnc.Degree() + xEnc.Degree(), context.MaxLevel());
        evaluator.Mul(&xEnc, &xEnc, &cipherMult, MultiType::ciphertext);
        evaluator.Relinearize(&cipherMult, &xEnc);
        decryptor.Decrypt(&xEnc, &result);
        evaluator.lightEncoder->ScaleDown(&result, &result);
        std::cout << "再平方" << i + 1 << "次, " << basicSlotRing.ExtractSlotValue(result.value->Coeffs[0], 0)[0] <<
            std::endl;
    }
}

/*
 * @brief 测试BFV基本算子
 *
 */
void TestScheme::TestBFV()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    for (Context *p : defaultParams) {
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }

        TestEvaluator(testctx);
    }
}
/*
 * @brief 测试密钥相关功能与速度
 * 1、私钥生成
 * 2、公钥生成
 * 3、公钥加密
 * 4、解密
 */
void TestScheme::TestEncrypt()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    for (Context *p : defaultParams) {
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }
        KeyGenerator keygen(p);
        KeyedPRNG *prng = new KeyedPRNG();
        TernarySampler *ternarySampler = new TernarySampler(prng, keygen.parameters->ringQ, 1 / 3);
        auto start = std::chrono::high_resolution_clock::now();
        SecretKey *sk = keygen.genSecretKeyFromSampler(ternarySampler);
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "CreateSecretKey:" << std::setw(10) << std::right << duration << "us" <<
            endl;

        start = std::chrono::high_resolution_clock::now();
        PublicKey *pk = keygen.GenPublicKey(sk);
        end = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "CreatePublicKey:" << std::setw(10) << std::right << duration << "us" <<
            endl;

        start = std::chrono::high_resolution_clock::now();
        RelinearizationKey *rlk = testctx->kgen->GenRelinearizationKey(testctx->sk, 1);
        end = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "CreateRelinKey:" << std::setw(10) << std::right << duration << "us" <<
            endl;

        vector<uint64_t> random{ 257 };
        start = std::chrono::high_resolution_clock::now();
        GaloisKeys *gk = testctx->kgen->GenGaloisKeys(random, testctx->sk);
        end = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "CreateGaloisKey:" << std::setw(10) << std::right << duration << "us" <<
            endl;

        Poly *coeffs = testctx->uSampler->ReadNew();
        Poly *result = new Poly(testctx->params->N(), testctx->params->QCount());
        PlaintextRingT *plaintext = new PlaintextRingT(testctx->params, testctx->params->QCount() - 1);
        testctx->encoder->EncodeUintRingT(coeffs->Coeffs[0], plaintext);

        start = std::chrono::high_resolution_clock::now();
        testctx->encoder->ScaleUp(plaintext, plaintext);
        Ciphertext *ciphertext1 = testctx->encryptorPk->EncryptNew(plaintext);
        end = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "EncryprPublic:" << std::setw(10) << std::right << duration << "us" <<
            endl;

        start = std::chrono::high_resolution_clock::now();
        testctx->decryp->Decrypt(ciphertext1, plaintext);
        testctx->encoder->ScaleDown(plaintext, plaintext);
        end = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "Decrypt:" << std::setw(10) << std::right << duration << "us" << endl;

        plaintext->value->Coeffs.resize(1);
        testctx->encoder->params->ringT->NTT(plaintext->value, testctx->encoder->tmpPoly);

        for (uint64_t i = 0; i < testctx->encoder->params->ringQ->N; i++) {
            result->Coeffs[0][i] = testctx->encoder->tmpPoly->Coeffs[0][testctx->encoder->indexMatrix[i]];
        }
        assert(result->Coeffs[0][0] == coeffs->Coeffs[0][0]);
    }
}
/*
 * @brief 测试私钥密钥加密速度
 * 1、私钥加密
 */
void TestScheme::TestSkEncrypt()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    for (Context *p : defaultParams) {
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }

        std::cout << "            TestSkEncrypt..." << std::endl;
        KeyGenerator keygen(p);
        KeyedPRNG *prng = new KeyedPRNG();
        TernarySampler *ternarySampler = new TernarySampler(prng, keygen.parameters->ringQ, 1 / 3);
        SecretKey *sk = keygen.genSecretKeyFromSampler(ternarySampler);
        PublicKey *pk = keygen.GenPublicKey(sk);

        Poly *coeffs = testctx->uSampler->ReadNew();
        Poly *result = new Poly(testctx->params->N(), testctx->params->QCount());
        PlaintextRingT *plaintext = new PlaintextRingT(testctx->params, testctx->params->QCount() - 1);
        testctx->encoder->EncodeUintRingT(coeffs->Coeffs[0], plaintext);
        testctx->encoder->ScaleUp(plaintext, plaintext);
        auto start = std::chrono::high_resolution_clock::now();
        Ciphertext *ciphertext1 = testctx->encryptorSk->EncryptNew(plaintext);
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "EncryprSk:" << std::setw(10) << std::right << duration << "us" << endl;
        testctx->decryp->Decrypt(ciphertext1, plaintext);
        testctx->encoder->ScaleDown(plaintext, plaintext);
        plaintext->value->Coeffs.resize(1);
        testctx->encoder->params->ringT->NTT(plaintext->value, testctx->encoder->tmpPoly);
        VerifyTestVectors(testctx, testctx->decryp, coeffs, ciphertext1);
    }
}
/*
 * @brief 测试密文同态乘法以及重现性化正确性与速度
 *
 */
void TestScheme::TestMultRelin()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    for (Context *p : defaultParams) {
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }

        std::cout << "            TestRelinearize ..." << std::endl;
        if (testctx->params->PCount() == 0) {
            throw std::runtime_error("#Pi is empty");
        }

        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *ciphertext2 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values2, nullptr));

        Ciphertext *receiver =
            new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext2->Degree(), testctx->params->MaxLevel());
        
            auto start = std::chrono::high_resolution_clock::now();
        testctx->evaluator->Mul(ciphertext1, ciphertext2, receiver, MultiType::ciphertext);
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "EvaluateMultCt:" << std::setw(10) << std::right << duration << "us" <<
            endl;

        testctx->ringT->MulCoeffs(values1, values2, values1);

        start = std::chrono::high_resolution_clock::now();
        Ciphertext *receiver2 = testctx->evaluator->RelinearizeNew(receiver);
        end = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "EvaluateRelin:" << std::setw(10) << std::right << duration << "us" <<
            endl;
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver2);

        testctx->evaluator->Relinearize(receiver, receiver);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver2);
    }
}
/*
 * @brief 测试密文平方
 *
 */
void TestScheme::TestMultSquare()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    int i = 0;
    for (Context *p : defaultParams) {
        i++;
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }

        std::cout << "            TestRelinearize ..."
                  << "i = " << i << std::endl;
        if (testctx->params->PCount() == 0) {
            throw std::runtime_error("#Pi is empty");
        }

        std::cout << "            TestMulSquare (Ct, Ct)..." << std::endl;
        Poly *values1 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *receiver = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext1->Degree(),
            testctx->params->QCount() - 1);
        testctx->evaluator->Mul(ciphertext1, ciphertext1, receiver, MultiType::ciphertext);
        testctx->ringT->MulCoeffs(values1, values1, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver);
        Ciphertext *receiver2 = testctx->evaluator->RelinearizeNew(receiver);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver2);
        Ciphertext *receiver3 = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext1->Degree(),
            testctx->params->QCount() - 1);
        testctx->evaluator->Mul(receiver2, receiver2, receiver3, MultiType::ciphertext);
        testctx->ringT->MulCoeffs(values1, values1, values1);

        VerifyTestVectors(testctx, testctx->decryp, values1, receiver3);
    }
}
/*
 * @brief 测试噪声平方执行的次数
 *
 */
void TestScheme::TestMultRepeat()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    int i = 0;
    for (Context *p : defaultParams) {
        i++;
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }

        std::cout << "            TestRelinearize ..."
                  << "i = " << i << std::endl;
        if (testctx->params->PCount() == 0) {
            throw std::runtime_error("#Pi is empty");
        }

        std::cout << "            TestMulSquare (Ct, Ct)..." << std::endl;
        Poly *values1 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *receiver = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext1->Degree(),
            testctx->params->QCount() - 1);
        testctx->evaluator->Mul(ciphertext1, ciphertext1, receiver, MultiType::ciphertext);
        testctx->ringT->MulCoeffs(values1, values1, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver);
        receiver = testctx->evaluator->RelinearizeNew(receiver);
        Ciphertext *relin = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext1->Degree(),
            testctx->params->QCount() - 1);
        for (int mul = 0; mul < 22; mul++) {
            cout << "mul times: " << mul + 2 << endl;

            testctx->evaluator->Mul(receiver, receiver, relin, MultiType::ciphertext);
            testctx->ringT->MulCoeffs(values1, values1, values1);
            VerifyTestVectors(testctx, testctx->decryp, values1, relin);
            receiver = testctx->evaluator->RelinearizeNew(relin);
            VerifyTestVectors(testctx, testctx->decryp, values1, receiver);
        }
    }
}
/*
 * @brief 测试密文乘明文，密文乘RingT上明文与SEAL对应
 *
 */
void TestScheme::TestMulPt()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    for (Context *p : defaultParams) {
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }

        std::cout << "            TestMul (Ct, Pt)..." << std::endl;

        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Poly *values3 = nullptr;
        Ciphertext *ciphertext1 = nullptr;
        Plaintext *plaintext2 = nullptr;
        Plaintext *plaintextT = nullptr;

        ciphertext1 = static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        plaintext2 = static_cast<Plaintext *>(NewTestVectorsRingQ(testctx, nullptr, values2, nullptr));
        plaintextT = NewTestVectorsRingT(testctx, values3);

        auto start = std::chrono::high_resolution_clock::now();
        testctx->evaluator->Mul(ciphertext1, plaintext2, ciphertext1, MultiType::plaintext);
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "EvaluateMultPtQ:" << std::setw(10) << std::right << duration << "us" <<
            endl;
        testctx->ringT->MulCoeffs(values1, values2, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);

        start = std::chrono::high_resolution_clock::now();
        testctx->evaluator->Mul(ciphertext1, plaintextT, ciphertext1, MultiType::plaintextRingT);
        end = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "EvaluateMultPtT(SEAL):" << std::setw(10) << std::right << duration <<
            "us" << endl;
        testctx->ringT->MulCoeffs(values1, values3, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);
    }
}
/*
 * @brief 测试密文加明文，密文加RingT上的明文与SEAL对应
 *
 */
void TestScheme::TestAddPt()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    int i = 0;
    for (Context *p : defaultParams) {
        i++;
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }

        std::cout << "            TestAdd (Ct, Pt)..." << std::endl;

        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Poly *values3 = nullptr;
        Ciphertext *ciphertext1 = nullptr;
        Plaintext *plaintext2 = nullptr;
        Plaintext *plaintextT = nullptr;

        ciphertext1 = static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        plaintext2 = static_cast<Plaintext *>(NewTestVectorsRingQ(testctx, nullptr, values2, nullptr));
        plaintextT = NewTestVectorsRingT(testctx, values3);

        auto start = std::chrono::high_resolution_clock::now();
        testctx->evaluator->Add(ciphertext1, plaintext2, ciphertext1);
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "EvaluateAddPtQ:" << std::setw(10) << std::right << duration << "us" <<
            endl;
        testctx->ringT->Add(values1, values2, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);

        start = std::chrono::high_resolution_clock::now();
        testctx->encoder->ScaleUp(plaintextT, plaintextT);
        testctx->evaluator->Add(ciphertext1, plaintextT, ciphertext1);
        end = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "EvaluateAddPtT(SEAL):" << std::setw(10) << std::right << duration <<
            "us" << endl;
        testctx->ringT->Add(values1, values3, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);
    }
}
/*
 * @brief 测试密文加密文，密文加密文与SEAL对应
 *
 */
void TestScheme::TestAddCt()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    int i = 0;
    for (Context *p : defaultParams) {
        i++;
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }

        std::cout << "            TestAdd (Ct, Ct)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *ciphertext2 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values2, nullptr));
        Ciphertext *receiver = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext2->Degree(),
            testctx->params->QCount() - 1);

        auto start = std::chrono::high_resolution_clock::now();
        testctx->evaluator->Add(ciphertext1, ciphertext2, receiver);
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
        cout << std::setw(35) << std::left << "EvaluateAddCt:" << std::setw(10) << std::right << duration << "us" <<
            endl;
        testctx->ringT->Add(values1, values2, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver);
    }
}
/*
 * @brief 测试密钥交换功能
 *
 */
void TestScheme::TestSwitchKey()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    int i = 0;
    for (Context *p : defaultParams) {
        i++;
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }

        if (testctx->params->PCount() == 0) {
            throw std::runtime_error("#Pi is empty");
        }

        std::cout << "            TestSwitchKey..." << std::endl;

        SecretKey *sk2 = testctx->kgen->GenSecretKey();
        Decryptor *decryptorSk2 = new Decryptor(testctx->params, sk2);
        SwitchingKey *switchKey = testctx->kgen->GenSwitchingKey(testctx->sk, sk2);

        // "Evaluator/KeySwitch/InPlace"
        {
            std::cout << "            TestKeySwitch InPlace ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));
            testctx->evaluator->SwitchKeys(ciphertext, switchKey, ciphertext);
            VerifyTestVectors(testctx, decryptorSk2, values, ciphertext);
        }

        // "Evaluator/KeySwitch/New"
        {
            std::cout << "            TestKeySwitchNew ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));
            ciphertext = testctx->evaluator->SwitchKeysNew(ciphertext, switchKey);
            VerifyTestVectors(testctx, decryptorSk2, values, ciphertext);
        }
    }
}
/*
 * @brief 测试同态旋转的速度
 *
 */
void TestScheme::TestRotateTime()
{
    std::vector<Context *> defaultParams(testParams.begin() + 4, testParams.begin() + 5);

    // Test case 6: Rotate
    for (Context *p : defaultParams) {
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }
        if (testctx->params->PCount() == 0) {
            throw std::runtime_error("#Pi is empty");
        }

        int index = RandInt64(testctx->uSampler->prng, 255);
        std::vector<int> rots = { index };

        RotationKeySet *rotkey = testctx->kgen->GenRotationKeysForRotations(rots, true, testctx->sk);
        testctx->evaluator->WithKey(new EvaluationKey(testctx->rlk, rotkey));

        // Test RotateRows
        {
            std::cout << "            TestRotateRows ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));

            auto start = std::chrono::high_resolution_clock::now();
            testctx->evaluator->RotateRows(ciphertext, ciphertext);
            auto end = std::chrono::high_resolution_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
            cout << std::setw(35) << std::left << "EvaluateRotateRows" << std::setw(10) << std::right << duration <<
                "us" << endl;

            std::vector<uint64_t> firstHalf(values->Coeffs[0].begin(),
                values->Coeffs[0].begin() + (testctx->params->N() >> 1));
            std::vector<uint64_t> secondHalf(values->Coeffs[0].begin() + (testctx->params->N() >> 1),
                values->Coeffs[0].end());
            values->Coeffs[0].clear();
            values->Coeffs[0].insert(values->Coeffs[0].end(), secondHalf.begin(), secondHalf.end());
            values->Coeffs[0].insert(values->Coeffs[0].end(), firstHalf.begin(), firstHalf.end());
            VerifyTestVectors(testctx, testctx->decryp, values, ciphertext);
        }

        // Test RotateRowsNew
        {
            std::cout << "            TestRotateRowsNew ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));
            auto start = std::chrono::high_resolution_clock::now();
            ciphertext = testctx->evaluator->RotateRowsNew(ciphertext);
            auto end = std::chrono::high_resolution_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
            cout << std::setw(35) << std::left << "TestRotateRowsNew" << std::setw(10) << std::right << duration <<
                "us" << endl;    

            std::vector<uint64_t> firstHalf(values->Coeffs[0].begin(),
                values->Coeffs[0].begin() + (testctx->params->N() >> 1));
            std::vector<uint64_t> secondHalf(values->Coeffs[0].begin() + (testctx->params->N() >> 1),
                values->Coeffs[0].end());
            values->Coeffs[0].clear();
            values->Coeffs[0].insert(values->Coeffs[0].end(), secondHalf.begin(), secondHalf.end());
            values->Coeffs[0].insert(values->Coeffs[0].end(), firstHalf.begin(), firstHalf.end());
            VerifyTestVectors(testctx, testctx->decryp, values, ciphertext);
        }

        // Test RotateColumns
        {
            std::cout << "            TestRotateColumns ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));
            Ciphertext *receiver = new Ciphertext(testctx->params, 1, testctx->params->QCount() - 1);

            for (int &n : rots) {
                auto start = std::chrono::high_resolution_clock::now();
                testctx->evaluator->RotateColumns(ciphertext, n, receiver);
                auto end = std::chrono::high_resolution_clock::now();
                auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
                cout << std::setw(35) << std::left << "EvaluateRotateCols" << std::setw(10) << std::right << duration <<
                    "us" << endl;

                std::vector<uint64_t> valuesWant = RotateUint64Slots(values->Coeffs[0], n);
                Poly *valuePoly = new Poly();
                valuePoly->Coeffs.resize(1);
                valuePoly->Coeffs[0].assign(valuesWant.begin(), valuesWant.end());

                VerifyTestVectors(testctx, testctx->decryp, valuePoly, receiver);
            }
        }

        // Test RotateColumnsNew
        {
            std::cout << "            TestRotateColumnsNew ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));

            for (int &n : rots) {
                auto start = std::chrono::high_resolution_clock::now();
                Ciphertext *receiver = testctx->evaluator->RotateColumnsNew(ciphertext, n);
                auto end = std::chrono::high_resolution_clock::now();
                auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
                cout << std::setw(35) << std::left << "TestRotateColumnsNew" << std::setw(10) << std::right << duration <<
                "us" << endl;    
                
                std::vector<uint64_t> valuesWant = RotateUint64Slots(values->Coeffs[0], n);
                Poly *valuePoly = new Poly();
                valuePoly->Coeffs.resize(1);
                valuePoly->Coeffs[0].assign(valuesWant.begin(), valuesWant.end());

                VerifyTestVectors(testctx, testctx->decryp, valuePoly, receiver);
            }
        }

        rotkey = testctx->kgen->GenRotationKeysForInnerSum(testctx->sk);
        testctx->evaluator->WithKey(new EvaluationKey(testctx->rlk, rotkey));
    }
}
/*
 * @brief 测试自举编码下的部分算子正确性（密文加密文，密文加明文，密文乘密文，密文乘明文）
 *
 */
void TestScheme::Test128BFV()
{
    cout << "--------------开始128槽测试-------------------" << endl;
    std::vector<Context *> defaultParams(testBootstrapParams.begin(), testBootstrapParams.begin() + 1);

    for (Context *p : defaultParams) {
        TestContext *testctx = nullptr;
        try {
            testctx = GenTestParams(p);
        } catch (std::exception &e) {
            throw std::runtime_error("Failed to generate test parameters: " + std::string(e.what()));
        }
        Evaluator evaluator(testctx->params, new EvaluationKey(testctx->rlk, nullptr));

        TestEvaluator128(testctx);
        TestRotate128(testctx);
    }
}
/*
 * @brief 生成测试参数
 *
 * 根据输入的参数生成测试所需的各种对象实例,包括密钥生成器、编码器等
 *
 * @param params 加密方案的参数
 * @return TestContext* 返回测试上下文对象
 */
TestScheme::TestContext *TestScheme::GenTestParams(Context *params)
{
    TestContext *testctx = new TestContext();
    testctx->params = params;

    testctx->prng = new KeyedPRNG();

    testctx->ringQ = new Ring(params->N(), params->qi);
    testctx->ringP = new Ring(params->N(), params->pi);

    std::vector<uint64_t> tpm_p;
    tpm_p.insert(tpm_p.end(), params->qi.begin(), params->qi.end());
    tpm_p.insert(tpm_p.end(), params->pi.begin(), params->pi.end());

    testctx->ringQP = new Ring(params->N(), tpm_p);

    testctx->ringT = new Ring(params->N(), std::vector<uint64_t>{ params->t });

    testctx->uSampler = new UniformSampler(testctx->prng, testctx->ringT);

    testctx->kgen = new KeyGenerator(testctx->params);
    std::pair<SecretKey *, PublicKey *> tmp = testctx->kgen->GenKeyPair();
    testctx->sk = tmp.first;
    testctx->pk = tmp.second;

    if (params->PCount() != 0) {
        testctx->rlk = testctx->kgen->GenRelinearizationKey(testctx->sk, 1);
    }

    testctx->encoder = new Encoder(testctx->params);
    testctx->encryptorPk = new PkEncryptor(testctx->params, testctx->pk);
    testctx->encryptorSk = new SkEncryptor(testctx->params, testctx->sk);
    testctx->decryp = new Decryptor(testctx->params, testctx->sk);
    testctx->evaluator = new Evaluator(testctx->params, new EvaluationKey(testctx->rlk, nullptr));

    return testctx;
}
/*
 * @brief 生成用于测试的环 Q 上的向量
 *
 * @param testctx 测试上下文对象指针,包含参数和加密所需的各种组件
 * @param encryptor 加密器指针,用于加密明文。如果为 nullptr 则返回明文
 * @param coeffs 输出参数,用于存储生成的多项式系数
 * @param plaintext 明文对象指针,用于存储编码后的RingQ上的明文
 *
 * @return void* 如果 encryptor 不为空则返回加密后的密文,否则返回RingQ上的明文
 */
void *TestScheme::NewTestVectorsRingQ(TestContext *testctx, Encryptor *encryptor, Poly *&coeffs, Plaintext *plaintext)
{
    coeffs = testctx->uSampler->ReadNew();
    plaintext = new Plaintext(testctx->params, testctx->params->QCount() - 1);
    testctx->encoder->EncodeUint(coeffs->Coeffs[0], plaintext);
    if (encryptor != nullptr) {
        return testctx->encryptorPk->EncryptNew(plaintext);
    }
    return plaintext;
}
/*
 * @brief 生成测试用的明文环T上的向量
 * @param testctx 测试上下文,包含参数和编码器等
 * @param coeffs 输出参数,用于存储生成的系数多项式
 * @return PlaintextRingT* 返回编码后的RingT的明文对象指针
 */
PlaintextRingT *TestScheme::NewTestVectorsRingT(TestContext *testctx, Poly *&coeffs)
{
    coeffs = testctx->uSampler->ReadNew();

    PlaintextRingT *plaintext = new PlaintextRingT(testctx->params, testctx->params->QCount() - 1);

    testctx->encoder->EncodeUintRingT(coeffs->Coeffs[0], plaintext);

    return plaintext;
}
/*
 * @brief 验证同态加密计算结果的正确性
 *
 * 该函数通过比较解密后的密文与预期的明文是否相等来验证同态加密计算的正确性。
 * 如果提供了解密器(decryptor)，则先解密密文再进行比较；否则直接比较明文。
 *
 * @param testctx 测试上下文,包含编码器等组件
 * @param decryptor 解密器,用于解密密文。如果为nullptr则表示直接比较明文
 * @param coeffs 预期的明文多项式系数
 * @param element 待验证的密文或明文
 */
void TestScheme::VerifyTestVectors(TestContext *testctx, Decryptor *decryptor, Poly *coeffs, Ciphertext *element)
{
    std::vector<uint64_t> coeffsTest;
    if (decryptor != nullptr) {
        coeffsTest = testctx->encoder->DecodeUintNew(decryptor->DecryptNew(element));
    } else {
        coeffsTest = testctx->encoder->DecodeUintNew(element);
    }
    if (!EqualSliceUint64(coeffs->Coeffs[0], coeffsTest)) {
        std::cout << "NO PASS!" << std::endl;
    } else {
        std::cout << "PASS!" << std::endl;
    }
}
/*
 * @brief BFV算子测试函数，主要测试功能有
 * 1、密文加密文、密文加密文不取模、密文加明文、密文加明文不取模
 * 2、密文减密文、密文减密文不取模、密文减明文、密文减明文不取模
 * 3、密文取反
 * 4、密文乘密文、密文乘明文、密文乘常数，密文的平方，重线性化
 * 5、密钥交换
 * 6、同态列旋转、同态行旋转
 * @param testctx 测试相关参数
 */
void TestScheme::TestEvaluator(TestContext *testctx)
{
    // Test case 1: Evaluator Add
    // Add (Ct, Ct)
    {
        std::cout << "            TestAdd (Ct, Ct)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *ciphertext2 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values2, nullptr));
        Ciphertext *receiver = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext2->Degree(),
            testctx->params->QCount() - 1);

        auto start = std::chrono::high_resolution_clock::now();
        testctx->evaluator->Add(ciphertext1, ciphertext2, receiver);
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = end - start;
        cout << "同态加法密文加密文: " << std::chrono::duration_cast<std::chrono::microseconds>(duration).count() <<
            "us" << endl;
        testctx->ringT->Add(values1, values2, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver);
    }

    // AddNoMod (Ct, Ct)
    {
        std::cout << "            TestAddNoMod (Ct, Ct)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *ciphertext2 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values2, nullptr));

        testctx->evaluator->AddNoMod(ciphertext1, ciphertext2, ciphertext1);
        testctx->evaluator->Reduce(ciphertext1, ciphertext1);
        testctx->ringT->Add(values1, values2, values1);

        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);
    }

    // Add (Ciphertext, Plaintext)
    {
        std::cout << "            TestAdd (Ciphertext, Plaintext)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 = nullptr;
        Plaintext *plaintext2 = nullptr;

        // 初始化 ciphertext1 和 plaintext2
        ciphertext1 = static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        plaintext2 = static_cast<Plaintext *>(NewTestVectorsRingQ(testctx, nullptr, values2, nullptr));

        // 执行 Add(ciphertext1, plaintext2, ciphertext1)
        testctx->evaluator->Add(ciphertext1, plaintext2, ciphertext1);
        testctx->ringT->Add(values1, values2, values1);

        // 验证 Add(ciphertext1 - plaintext2) 的结果
        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);

        // 执行 Add(plaintext2, ciphertext1, ciphertext1)
        testctx->evaluator->Add(plaintext2, ciphertext1, ciphertext1);
        testctx->ringT->Add(values2, values1, values2);

        // 验证 Add(plaintext2 - ciphertext1) 的结果
        VerifyTestVectors(testctx, testctx->decryp, values2, ciphertext1);
    }


    // Test case 2: Evaluator Sub
    // Sub (Ct, Ct)
    {
        std::cout << "            TestSub (Ct, Ct)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *ciphertext2 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values2, nullptr));

        testctx->evaluator->Sub(ciphertext1, ciphertext2, ciphertext1);
        testctx->ringT->Sub(values1, values2, values1);

        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);
    }

    // SubNoMod (Ct, Ct)
    {
        std::cout << "            TestSubNoMod (Ct, Ct)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *ciphertext2 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values2, nullptr));

        testctx->evaluator->SubNoMod(ciphertext1, ciphertext2, ciphertext1);
        testctx->evaluator->Reduce(ciphertext1, ciphertext1);
        testctx->ringT->Sub(values1, values2, values1);

        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);
    }

    // Sub (Ciphertext, Plaintext)
    {
        std::cout << "            TestSub (Ciphertext, Plaintext)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 = nullptr;
        Plaintext *plaintext2 = nullptr;

        // 初始化 ciphertext1 和 plaintext2
        ciphertext1 = static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        plaintext2 = static_cast<Plaintext *>(NewTestVectorsRingQ(testctx, nullptr, values2, nullptr));

        // 执行 Sub(ciphertext1, plaintext2, ciphertext1)
        testctx->evaluator->Sub(ciphertext1, plaintext2, ciphertext1);
        testctx->ringT->Sub(values1, values2, values1);

        // 验证 Sub(ciphertext1 - plaintext2) 的结果
        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);

        // 执行 Sub(plaintext2, ciphertext1, ciphertext1)
        testctx->evaluator->Sub(plaintext2, ciphertext1, ciphertext1);
        testctx->ringT->Sub(values2, values1, values2);

        // 验证 Sub(plaintext2 - ciphertext1) 的结果
        VerifyTestVectors(testctx, testctx->decryp, values2, ciphertext1);
    }

    // SubNoMod (Ciphertext, Plaintext)
    {
        std::cout << "            TestSubNoMod (Ciphertext, Plaintext)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 = nullptr;
        Plaintext *plaintext2 = nullptr;

        // 初始化 ciphertext1 和 plaintext2
        ciphertext1 = static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        plaintext2 = static_cast<Plaintext *>(NewTestVectorsRingQ(testctx, nullptr, values2, nullptr));

        // 执行 SubNoMod(ciphertext1, plaintext2, ciphertext1)
        testctx->evaluator->SubNoMod(ciphertext1, plaintext2, ciphertext1);
        // 对结果进行 Reduce
        testctx->evaluator->Reduce(ciphertext1, ciphertext1);
        testctx->ringT->Sub(values1, values2, values1);

        // 验证 SubNoMod(ciphertext1 - plaintext2) 的结果
        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);

        // 执行 SubNoMod(plaintext2, ciphertext1, ciphertext1)
        testctx->evaluator->SubNoMod(plaintext2, ciphertext1, ciphertext1);
        // 对结果进行 Reduce
        testctx->evaluator->Reduce(ciphertext1, ciphertext1);
        testctx->ringT->Sub(values2, values1, values2);

        // 验证 SubNoMod(plaintext2 - ciphertext1) 的结果
        VerifyTestVectors(testctx, testctx->decryp, values2, ciphertext1);
    }


    // Test case 3: Evaluator Neg
    {
        std::cout << "            TestNeg ..." << std::endl;
        Poly *values1 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));

        testctx->evaluator->Neg(ciphertext1, ciphertext1);
        testctx->ringT->Neg(values1, values1);
        testctx->ringT->Reduce(values1, values1);

        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);
    }

    // Test case 4: Evaluator Mul
    // Mul (Ct, Ct)
    {
        std::cout << "            TestMul (Ct, Ct)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *ciphertext2 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values2, nullptr));
        Ciphertext *receiver = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext2->Degree(),
            testctx->params->QCount() - 1);
        auto start = std::chrono::high_resolution_clock::now();
        testctx->evaluator->Mul(ciphertext1, ciphertext2, receiver, MultiType::ciphertext);
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = end - start;
        cout << "同态乘法MultCt" << std::chrono::duration_cast<std::chrono::microseconds>(duration).count() << "us" <<
            endl;
        testctx->ringT->MulCoeffs(values1, values2, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver);
    }

    //         Mul (Ciphertext, Plaintext)
    {
        std::cout << "            TestMul (Ciphertext, Plaintext)..." << std::endl;
        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 = nullptr;
        Plaintext *plaintext2 = nullptr;

        ciphertext1 = static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        plaintext2 = static_cast<Plaintext *>(NewTestVectorsRingQ(testctx, nullptr, values2, nullptr));

        testctx->evaluator->Mul(ciphertext1, plaintext2, ciphertext1, MultiType::plaintext);

        testctx->ringT->MulCoeffs(values1, values2, values1);

        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);
    }

    // MulScalar (Ciphertext, Scalar)
    {
        std::cout << "            TestMulScalar (Ciphertext, Scalar)..." << std::endl;
        Poly *values1 = nullptr;
        Ciphertext *ciphertext1 = nullptr;

        // 初始化 ciphertext1 和 values1
        ciphertext1 = static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));

        // 执行 MulScalar(ciphertext1, 37, ciphertext1)
        testctx->evaluator->MulScalar(ciphertext1, 37, ciphertext1);

        // 在 ringT 上执行 MulScalar(values1, 37, values1)
        testctx->ringT->MulScalar(values1, 37, values1);

        // 验证 MulScalar 操作的结果是否正确
        VerifyTestVectors(testctx, testctx->decryp, values1, ciphertext1);
    }

    // MulSquare (Ct, Ct)
    {
        std::cout << "            TestMulSquare (Ct, Ct)..." << std::endl;
        Poly *values1 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *receiver = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext1->Degree(),
            testctx->params->QCount() - 1);
        testctx->evaluator->Mul(ciphertext1, ciphertext1, receiver, MultiType::ciphertext);

        testctx->ringT->MulCoeffs(values1, values1, values1);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver);
        Ciphertext *receiver2 = testctx->evaluator->RelinearizeNew(receiver);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver2);
        // 检查参数中的 logN 是否小于 13，如果是，则跳过后续测试
        if (testctx->params->logN >= 13) {
            Ciphertext *receiver3 = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext1->Degree(),
                testctx->params->QCount() - 1);
            testctx->evaluator->Mul(receiver2, receiver2, receiver3, MultiType::ciphertext);
            testctx->ringT->MulCoeffs(values1, values1, values1);
            //                Ciphertext* receiver4 = testctx->evaluator->RelinearizeNew(receiver3);
            VerifyTestVectors(testctx, testctx->decryp, values1, receiver3);
        }
    }

    // Relinearize
    {
        std::cout << "            TestRelinearize ..." << std::endl;
        if (testctx->params->PCount() == 0) {
            throw std::runtime_error("#Pi is empty");
        }

        Poly *values1 = nullptr;
        Poly *values2 = nullptr;
        Ciphertext *ciphertext1 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values1, nullptr));
        Ciphertext *ciphertext2 =
            static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values2, nullptr));
        testctx->ringT->MulCoeffs(values1, values2, values1);
        Ciphertext *receiver =
            new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext2->Degree(), testctx->params->MaxLevel());
        auto start = std::chrono::high_resolution_clock::now();

        testctx->evaluator->Mul(ciphertext1, ciphertext2, receiver, MultiType::ciphertext);
        Ciphertext *receiver2 = testctx->evaluator->RelinearizeNew(receiver);
        auto end = std::chrono::high_resolution_clock::now();
        auto duration = end - start;
        cout << "同态乘法MultCt+relin" << std::chrono::duration_cast<std::chrono::microseconds>(duration).count() <<
            "us" << endl;
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver2);

        testctx->evaluator->Relinearize(receiver, receiver);
        VerifyTestVectors(testctx, testctx->decryp, values1, receiver);
    }


    // Test case 5: Key Switch
    {
        if (testctx->params->PCount() == 0) {
            throw std::runtime_error("#Pi is empty");
        }

        SecretKey *sk2 = testctx->kgen->GenSecretKey();
        Decryptor *decryptorSk2 = new Decryptor(testctx->params, sk2);
        SwitchingKey *switchKey = testctx->kgen->GenSwitchingKey(testctx->sk, sk2);

        // "Evaluator/KeySwitch/InPlace"
        {
            std::cout << "            TestKeySwitch InPlace ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));
            testctx->evaluator->SwitchKeys(ciphertext, switchKey, ciphertext);
            VerifyTestVectors(testctx, decryptorSk2, values, ciphertext);
        }

        // "Evaluator/KeySwitch/New"
        {
            std::cout << "            TestKeySwitchNew ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));
            ciphertext = testctx->evaluator->SwitchKeysNew(ciphertext, switchKey);
            VerifyTestVectors(testctx, decryptorSk2, values, ciphertext);
        }
    }

    // Test case 6: Rotate
    {
        if (testctx->params->PCount() == 0) {
            throw std::runtime_error("#Pi is empty");
        }

        std::vector<int> rots = { 1, -1, 4, -4, 63, -63 };
        RotationKeySet *rotkey = testctx->kgen->GenRotationKeysForRotations(rots, true, testctx->sk);
        testctx->evaluator->WithKey(new EvaluationKey(testctx->rlk, rotkey));

        // Test RotateRows
        {
            std::cout << "            TestRotateRows ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));

            auto start = std::chrono::high_resolution_clock::now();
            testctx->evaluator->RotateRows(ciphertext, ciphertext);
            auto end = std::chrono::high_resolution_clock::now();
            auto duration = end - start;
            cout << "同态旋转RotateRows" << std::chrono::duration_cast<std::chrono::microseconds>(duration).count() <<
                "us" << endl;

            std::vector<uint64_t> firstHalf(values->Coeffs[0].begin(),
                values->Coeffs[0].begin() + (testctx->params->N() >> 1));
            std::vector<uint64_t> secondHalf(values->Coeffs[0].begin() + (testctx->params->N() >> 1),
                values->Coeffs[0].end());
            values->Coeffs[0].clear();
            values->Coeffs[0].insert(values->Coeffs[0].end(), secondHalf.begin(), secondHalf.end());
            values->Coeffs[0].insert(values->Coeffs[0].end(), firstHalf.begin(), firstHalf.end());
            VerifyTestVectors(testctx, testctx->decryp, values, ciphertext);
        }

        // Test RotateRowsNew
        {
            std::cout << "            TestRotateRowsNew ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));
            ciphertext = testctx->evaluator->RotateRowsNew(ciphertext);

            std::vector<uint64_t> firstHalf(values->Coeffs[0].begin(),
                values->Coeffs[0].begin() + (testctx->params->N() >> 1));
            std::vector<uint64_t> secondHalf(values->Coeffs[0].begin() + (testctx->params->N() >> 1),
                values->Coeffs[0].end());
            values->Coeffs[0].clear();
            values->Coeffs[0].insert(values->Coeffs[0].end(), secondHalf.begin(), secondHalf.end());
            values->Coeffs[0].insert(values->Coeffs[0].end(), firstHalf.begin(), firstHalf.end());
            VerifyTestVectors(testctx, testctx->decryp, values, ciphertext);
        }

        // Test RotateColumns
        {
            std::cout << "            TestRotateColumns ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));
            Ciphertext *receiver = new Ciphertext(testctx->params, 1, testctx->params->QCount() - 1);

            for (int &n : rots) {
                auto start = std::chrono::high_resolution_clock::now();
                testctx->evaluator->RotateColumns(ciphertext, n, receiver);
                auto end = std::chrono::high_resolution_clock::now();
                auto duration = end - start;
                cout << "同态旋转RotateCols" <<
                    std::chrono::duration_cast<std::chrono::microseconds>(duration).count() << "us" << endl;

                std::vector<uint64_t> valuesWant = RotateUint64Slots(values->Coeffs[0], n);
                Poly *valuePoly = new Poly();
                valuePoly->Coeffs.resize(1);
                valuePoly->Coeffs[0].assign(valuesWant.begin(), valuesWant.end());

                VerifyTestVectors(testctx, testctx->decryp, valuePoly, receiver);
            }
        }

        // Test RotateColumnsNew
        {
            std::cout << "            TestRotateColumnsNew ..." << std::endl;
            Poly *values = nullptr;
            Ciphertext *ciphertext =
                static_cast<Ciphertext *>(NewTestVectorsRingQ(testctx, testctx->encryptorPk, values, nullptr));

            for (int &n : rots) {
                Ciphertext *receiver = testctx->evaluator->RotateColumnsNew(ciphertext, n);
                std::vector<uint64_t> valuesWant = RotateUint64Slots(values->Coeffs[0], n);
                Poly *valuePoly = new Poly();
                valuePoly->Coeffs.resize(1);
                valuePoly->Coeffs[0].assign(valuesWant.begin(), valuesWant.end());

                VerifyTestVectors(testctx, testctx->decryp, valuePoly, receiver);
            }
        }

        rotkey = testctx->kgen->GenRotationKeysForInnerSum(testctx->sk);
        testctx->evaluator->WithKey(new EvaluationKey(testctx->rlk, rotkey));
    }
}

/*
 * @brief 验证128槽数的同态加密计算结果的正确性
 *
 * 该函数通过比较解密后的密文与预期的明文是否相等来验证同态加密计算的正确性。
 * 如果提供了解密器(decryptor)，则先解密密文再进行比较；否则直接比较明文。
 *
 * @param testctx 测试上下文,包含编码器等组件
 * @param decryptor 解密器,用于解密密文。如果为nullptr则表示直接比较明文
 * @param coeffs 预期的明文多项式系数
 * @param element 待验证的密文或明文
 * @param slotRing 解码所需要的数据
 */
void TestScheme::VerifyTestVectors128(TestScheme::TestContext *testctx, Decryptor *decryptor, Poly *coeffs,
    Ciphertext *element, SlotRing *slotRing)
{
    std::vector<uint64_t> coeffsTest;
    if (decryptor != nullptr) {
        Plaintext *result = decryptor->DecryptNew(element);
        testctx->encoder->ScaleDown(result, result);
        coeffsTest = result->value->Coeffs[0];
    } else {
        throw std::runtime_error("解密器为空");
    }
    for (int i = 0; i < 128; i++) {
        uint64_t a = slotRing->ExtractSlotValue(coeffsTest, i)[0];
        if (coeffs->Coeffs[0][i] != a) {
            throw std::runtime_error("Verification failed: Coefficients do not match");
        }
    }
    std::cout << "PASS!" << std::endl;
}

/*
 * @brief BFV128槽编码算子测试函数，主要测试功能有
 * 1、自举的编解码
 * 2、密文加明文，密文加密文
 * 3、密文乘密文、密文乘明文
 * @param testctx 测试相关参数
 */
void TestScheme::TestEvaluator128(TestScheme::TestContext *testctx)
{
    // 初始化数据
    cout << "----------预处理数据正在生成-------------" << endl;
    std::shared_ptr<SlotRing> slotRing = P257TestParameters();
    SlotRing basic_slot_ring = slotRing->ChangeExponent(1);
    cout << "----------预处理数据生成完成-------------" << endl;

    // Test case 0: encode_decode_bootstrapping test
    {
        std::cout << "-----------测试自举中的编解码------------" << std::endl;
        vector<uint64_t> data;
        PolyAdd(data, slotRing->FromSlotValue({ 1 }, 0), slotRing->R().scalarMod);
        PolyAdd(data, slotRing->FromSlotValue({ 2 }, 1), slotRing->R().scalarMod);
        PolyAdd(data, slotRing->FromSlotValue({ 3 }, 2), slotRing->R().scalarMod);
        PolyAdd(data, slotRing->FromSlotValue({ 4 }, 3), slotRing->R().scalarMod);

        //        for (size_t i = 0; i < 128; ++i)
        //        {
        //            std::cout << slotRing->ExtractSlotValue(data, i)[0] << std::endl;
        //        }
        assert(slotRing->ExtractSlotValue(data, 0)[0] == 1);
        assert(slotRing->ExtractSlotValue(data, 1)[0] == 2);
        assert(slotRing->ExtractSlotValue(data, 2)[0] == 3);
        assert(slotRing->ExtractSlotValue(data, 3)[0] == 4);
        std::cout << "PASS!" << std::endl;
    }
    // Test case 1: Evaluator Add
    { // Add128 (Ct, Ct)
        { std::cout << "            TestAdd (Ct, Ct)..." << std::endl;
    Poly *values1 = new Poly(testctx->params->N(), 1);
    Poly *values2 = new Poly(testctx->params->N(), 1);
    Poly *values3 = new Poly(testctx->params->N(), 1);
    for (int i = 0; i < 128; i++) {
        values1->Coeffs[0][i] = i;
        values2->Coeffs[0][i] = i;
        values3->Coeffs[0][i] = (values1->Coeffs[0][i] + values2->Coeffs[0][i]) % 257;
    }
    vector<uint64_t> originalValues1;
    vector<uint64_t> originalValues2;
    vector<uint64_t> result;
    for (int i = 0; i < 128; i++) {
        PolyAdd(originalValues1, basic_slot_ring.FromSlotValue({ values1->Coeffs[0][i] }, i),
            basic_slot_ring.R().scalarMod);
        PolyAdd(originalValues2, basic_slot_ring.FromSlotValue({ values2->Coeffs[0][i] }, i),
            basic_slot_ring.R().scalarMod);
    }

    PlaintextRingT plaintextRingT1(originalValues1, testctx->params->QCount() - 1);
    PlaintextRingT plaintextRingT2(originalValues2, testctx->params->QCount() - 1);
    Plaintext plaintext1(testctx->params->N(), testctx->params->QCount() - 1);
    Plaintext plaintext2(testctx->params->N(), testctx->params->QCount() - 1);

    testctx->encoder->ScaleUp(&plaintextRingT1, &plaintext1);
    Ciphertext *ciphertext1 = testctx->encryptorPk->EncryptNew(&plaintext1);

    testctx->encoder->ScaleUp(&plaintextRingT2, &plaintext2);
    Ciphertext *ciphertext2 = testctx->encryptorPk->EncryptNew(&plaintext2);

    Ciphertext *ciphertextAdd = new Ciphertext(testctx->params, ciphertext1->Degree(), testctx->params->QCount() - 1);
    testctx->evaluator->Add(ciphertext1, ciphertext2, ciphertextAdd);

    VerifyTestVectors128(testctx, testctx->decryp, values3, ciphertextAdd, &basic_slot_ring);
}

// Add (Ciphertext, Plaintext)
{
    std::cout << "            TestAdd (Ciphertext, Plaintext)..." << std::endl;
    Poly *values1 = new Poly(testctx->params->N(), 1);
    Poly *values2 = new Poly(testctx->params->N(), 1);
    Poly *values3 = new Poly(testctx->params->N(), 1);
    for (int i = 0; i < 128; i++) {
        values1->Coeffs[0][i] = i;
        values2->Coeffs[0][i] = i;
        values3->Coeffs[0][i] = (values1->Coeffs[0][i] + values2->Coeffs[0][i]) % 257;
    }
    vector<uint64_t> originalValues1;
    vector<uint64_t> originalValues2;
    vector<uint64_t> result;
    for (int i = 0; i < 128; i++) {
        PolyAdd(originalValues1, basic_slot_ring.FromSlotValue({ values1->Coeffs[0][i] }, i),
            basic_slot_ring.R().scalarMod);
        PolyAdd(originalValues2, basic_slot_ring.FromSlotValue({ values2->Coeffs[0][i] }, i),
            basic_slot_ring.R().scalarMod);
    }

    PlaintextRingT plaintextRingT1(originalValues1, testctx->params->QCount() - 1);
    PlaintextRingT plaintextRingT2(originalValues2, testctx->params->QCount() - 1);
    Plaintext plaintext1(testctx->params->N(), testctx->params->QCount() - 1);
    Plaintext plaintext2(testctx->params->N(), testctx->params->QCount() - 1);

    testctx->encoder->ScaleUp(&plaintextRingT1, &plaintext1);
    Ciphertext *ciphertext1 = testctx->encryptorPk->EncryptNew(&plaintext1);

    Ciphertext *ciphertextAdd = new Ciphertext(testctx->params, ciphertext1->Degree(), testctx->params->QCount() - 1);

    testctx->encoder->ScaleUp(&plaintextRingT2, &plaintext2);
    testctx->evaluator->Add(ciphertext1, &plaintext2, ciphertextAdd);

    VerifyTestVectors128(testctx, testctx->decryp, values3, ciphertextAdd, &basic_slot_ring);
}
}
// Test case 4: Evaluator Mul
{
    // Mul (Ciphertext, Plaintext)
    {
        std::cout << "            TestMul (Ciphertext, Plaintext)..." << std::endl;
        Poly *values1 = new Poly(testctx->params->N(), 1);
        Poly *values2 = new Poly(testctx->params->N(), 1);
        Poly *values3 = new Poly(testctx->params->N(), 1);
        for (int i = 0; i < 128; i++) {
            values1->Coeffs[0][i] = i;
            values2->Coeffs[0][i] = i;
            values3->Coeffs[0][i] = (values1->Coeffs[0][i] * values2->Coeffs[0][i]) % 257;
        }
        vector<uint64_t> originalValues1;
        vector<uint64_t> originalValues2;
        vector<uint64_t> result;
        for (int i = 0; i < 128; i++) {
            PolyAdd(originalValues1, basic_slot_ring.FromSlotValue({ values1->Coeffs[0][i] }, i),
                basic_slot_ring.R().scalarMod);
            PolyAdd(originalValues2, basic_slot_ring.FromSlotValue({ values2->Coeffs[0][i] }, i),
                basic_slot_ring.R().scalarMod);
        }

        PlaintextRingT plaintextRingT1(originalValues1, testctx->params->QCount() - 1);
        PlaintextRingT plaintextRingT2(originalValues2, testctx->params->QCount() - 1);
        Plaintext plaintext1(testctx->params->N(), testctx->params->QCount() - 1);
        Plaintext plaintext2(testctx->params->N(), testctx->params->QCount() - 1);

        testctx->encoder->ScaleUp(&plaintextRingT1, &plaintext1);
        Ciphertext *ciphertext1 = testctx->encryptorPk->EncryptNew(&plaintext1);

        testctx->encoder->ScaleUp(&plaintextRingT2, &plaintext2);
        Ciphertext *ciphertext2 = testctx->encryptorPk->EncryptNew(&plaintext2);

        Ciphertext *ciphertextMul = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext2->Degree(),
            testctx->params->QCount() - 1);
        testctx->evaluator->Mul(ciphertext1, ciphertext2, ciphertextMul, MultiType::ciphertext);

        VerifyTestVectors128(testctx, testctx->decryp, values3, ciphertextMul, &basic_slot_ring);
    }

    // Relinearize
    {
        std::cout << "            TestRelinearize ..." << std::endl;
        Poly *values1 = new Poly(testctx->params->N(), 1);
        Poly *values2 = new Poly(testctx->params->N(), 1);
        Poly *values3 = new Poly(testctx->params->N(), 1);
        for (int i = 0; i < 128; i++) {
            values1->Coeffs[0][i] = i;
            values2->Coeffs[0][i] = i;
            values3->Coeffs[0][i] = (values1->Coeffs[0][i] * values2->Coeffs[0][i]) % 257;
        }
        vector<uint64_t> originalValues1;
        vector<uint64_t> originalValues2;
        vector<uint64_t> result;
        for (int i = 0; i < 128; i++) {
            PolyAdd(originalValues1, basic_slot_ring.FromSlotValue({ values1->Coeffs[0][i] }, i),
                basic_slot_ring.R().scalarMod);
            PolyAdd(originalValues2, basic_slot_ring.FromSlotValue({ values2->Coeffs[0][i] }, i),
                basic_slot_ring.R().scalarMod);
        }

        PlaintextRingT plaintextRingT1(originalValues1, testctx->params->QCount() - 1);
        PlaintextRingT plaintextRingT2(originalValues2, testctx->params->QCount() - 1);
        Plaintext plaintext1(testctx->params->N(), testctx->params->QCount() - 1);
        Plaintext plaintext2(testctx->params->N(), testctx->params->QCount() - 1);

        testctx->encoder->ScaleUp(&plaintextRingT1, &plaintext1);
        Ciphertext *ciphertext1 = testctx->encryptorPk->EncryptNew(&plaintext1);

        testctx->encoder->ScaleUp(&plaintextRingT2, &plaintext2);
        Ciphertext *ciphertext2 = testctx->encryptorPk->EncryptNew(&plaintext2);

        Ciphertext *ciphertextMul = new Ciphertext(testctx->params, ciphertext1->Degree() + ciphertext2->Degree(),
            testctx->params->QCount() - 1);
        testctx->evaluator->Mul(ciphertext1, ciphertext2, ciphertextMul, MultiType::ciphertext);

        testctx->evaluator->Relinearize(ciphertextMul, ciphertext1);

        VerifyTestVectors128(testctx, testctx->decryp, values3, ciphertext1, &basic_slot_ring);
    }
}
}
/*
 * @brief BFV128槽编码算子测试函数，主要测试功能有
 * 1、同态旋转，正常编码对应的左移，运用到自举编码则对应右移
 * @param testctx 测试相关参数
 */
void TestScheme::TestRotate128(TestScheme::TestContext *testctx)
{
    // 初始化数据
    cout << "----------预处理数据正在生成-------------" << endl;
    std::shared_ptr<SlotRing> slotRing = P257TestParameters();
    SlotRing basic_slot_ring = slotRing->ChangeExponent(1);
    cout << "----------预处理数据生成完成-------------" << endl;

    if (testctx->params->PCount() == 0) {
        throw std::runtime_error("#Pi is empty");
    }

    std::vector<int> rots = { 1, 3, 5, 6 };
    RotationKeySet *rotkey = testctx->kgen->GenRotationKeysForRotations(rots, true, testctx->sk);
    testctx->evaluator->WithKey(new EvaluationKey(testctx->rlk, rotkey));

    // Test RotateColumns
    {
        std::cout << "            TestRotateColumns ..." << std::endl;

        vector<uint64_t> values(testctx->params->N(), 0);
        values[0] = 1;
        values[1] = 2;
        values[2] = 3;
        values[3] = 4;

        vector<uint64_t> originalValues1;
        for (int i = 0; i < 128; i++) {
            PolyAdd(originalValues1, basic_slot_ring.FromSlotValue({ values[i] }, i), basic_slot_ring.R().scalarMod);
        }

        PlaintextRingT plaintextRingT1(originalValues1, testctx->params->QCount() - 1);
        Plaintext plaintext1(testctx->params->N(), testctx->params->QCount() - 1);
        testctx->encoder->ScaleUp(&plaintextRingT1, &plaintext1);
        Ciphertext *ciphertext1 = testctx->encryptorPk->EncryptNew(&plaintext1);

        //        Poly* values = nullptr;
        //        Ciphertext* ciphertext = static_cast<Ciphertext*>(NewTestVectorsRingQ128(testctx,
        //        testctx->encryptorPk, values, nullptr));
        Ciphertext *receiver = new Ciphertext(testctx->params, 1, testctx->params->QCount() - 1);

        for (int &n : rots) {
            testctx->evaluator->RotateColumns(ciphertext1, n, receiver);

            Poly *valuePoly = new Poly();
            valuePoly->Coeffs.resize(1);
            std::vector<uint64_t> tmp = RotateUint64Slice(values, -n);
            valuePoly->Coeffs[0] = tmp;
            VerifyTestVectors128(testctx, testctx->decryp, valuePoly, receiver, &basic_slot_ring);
        }
    }
}
